/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mia;

import java.sql.Statement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Greg Jarzab <greg.jarzab@gmail.com>
 */
public class QueryTester
{

    private boolean deadlockDetected;
    private String connectionURL;
    private ArrayList<Query> queryList;
    private ArrayList<Integer> queryOrder;

    public QueryTester( String connectionURL )
    {
        this.deadlockDetected = false;
        this.connectionURL = connectionURL;
        this.queryList = new ArrayList<Query>();
    }

    public void SetQueryOrder( ArrayList<Integer> order )
    {
        queryOrder = order;
    }

    public void AddQuery( Query q )
    {
        queryList.add( q );
    }

    private Query GetQuery( int index )
    {
        if ( index < 0 || index > queryList.size() )
        {
            return null;
        }

        return queryList.get( index );
    }

    public void RunTests( int threadCount, final boolean random )
    {
        try
        {
            /* Create threads used to run the tests waiting
             * one second after creating a new thread.
             */
            for ( int i = 0; i < threadCount; ++i )
            {
                new Thread( new Runnable()
                {

                    public void run()
                    {
                        RunTest( random );
                    }
                } ).start();

                Thread.sleep( 1000 );
            }
        } catch ( Exception e )
        {
            e.printStackTrace();
        }
    }

    private void RunTest( boolean random )
    {
        if( !random && null == queryOrder )
        {
            System.err.println( "You must first set the query order" );
            return;
        }

        int CurrentQuery = 0;
        
        Connection connection = null;
        Random rand = new Random( System.nanoTime() );

        try
        {
            // Create a new connection for this thread.
            // It might have been better to use connection pooling, but this should be fine for now
            connection = DriverManager.getConnection( connectionURL );
        } catch ( Exception e )
        {
            e.printStackTrace();
        }

        int queryIndex = 0;
        long startTime = 0;
        Statement statement = null;

        // Continue running test untill a deadlock is detected.
        // This will stop after all currently executing queries finish.
        while (!deadlockDetected)
        {
            if( !random )
            {
                queryIndex = queryOrder.get(  CurrentQuery++ % queryOrder.size() );
            }else
            {
                queryIndex = rand.nextInt( queryList.size() );
            }
            
            try
            {
                statement = connection.createStatement();

                // Report that the query was started.
                System.out.println( "S query#: " + queryIndex + " on " + Thread.currentThread().getName() );
                startTime = System.currentTimeMillis();
                statement.execute( GetQuery( queryIndex ).GetBody() );
                // Report that query finished and the time it took.
                System.out.println( "F query#: " + queryIndex + " on " + Thread.currentThread().getName() + " duration: " + ( System.currentTimeMillis() - startTime ) + " ms." );

            } catch ( SQLException e )
            {
                // Handle exceptions
                String sqlState = e.getSQLState();
                if ( sqlState.equals( "40001" ) )
                {
                    System.out.println( "Deadlock query#: " + queryIndex + " on " + Thread.currentThread().getName() );

                    try
                    {
                        connection.close();
                    }catch( SQLException exception )
                    {
                        System.err.println( "Error while closing connection" );
                    }

                    deadlockDetected = true;
                } else
                {
                    System.err.println( e.getMessage() );
                }
            }
        }

        try
        {
            statement.close();      // Close connection
        }catch( SQLException e )
        {
            e.printStackTrace();
        }
    }
}
